package com.example.coroutines

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.sync.withPermit
import org.junit.Test
import java.util.concurrent.atomic.AtomicInteger


/**
 * 协程并发安全
 * 协程并发默认是不安全的
 *
 * @author zhouronghua
 * @time 2022/1/4 8:15 下午
 */
class MultiCoroutineSafeTest {

    /**
     * 多协程并发默认是不安全的
     *
     * @author zhouronghua
     * @time 2022/1/4 8:21 下午
     */
    @Test
    fun test_unsafe_multi_coroutine() = runBlocking {
        var count = 0
        // 创建10000个并发协程，结果小于预期值
        List(10000) {
            GlobalScope.launch {
                count ++
            }
        }.joinAll()
        println("result $count")
    }

    /**
     * 测试原子安全
     * 说明：采用原子数保证多线程安全
     *
     * @author zhouronghua
     * @time 2022/1/4 8:22 下午
     */
    @Test
    fun test_atomic_safe_multi_coroutine() = runBlocking {
        var count = AtomicInteger()
        // 创建10000个并发协程，结果小于预期值
        List(10000) {
            GlobalScope.launch {
                count.incrementAndGet()
            }
        }.joinAll()
        println("result ${count.get()}")
    }

    /**
     * 测试Mutex安全
     * 说明：采用Mutex保证多线程安全
     *
     * @author zhouronghua
     * @time 2022/1/4 8:22 下午
     */
    @Test
    fun test_mutex_safe_multi_coroutine() = runBlocking {
        var mutex = Mutex()
        var count = 0
        // 创建10000个并发协程，结果小于预期值
        List(10000) {
            GlobalScope.launch {
                // 通过Mutex加锁后进行计算
                mutex.withLock {
                    count ++
                }
            }
        }.joinAll()
        println("result $count")
    }

    /**
     * 测试Semaphore安全
     * 说明：采用Semaphore保证多线程安全
     *
     * @author zhouronghua
     * @time 2022/1/4 8:22 下午
     */
    @Test
    fun test_semaphore_safe_multi_coroutine() = runBlocking {
        // 并发时一个线程同时运行
        var semaphore = Semaphore(1)
        var count = 0
        // 创建10000个并发协程，结果小于预期值
        List(10000) {
            GlobalScope.launch {
                // 通过Mutex加锁后进行计算
                semaphore.withPermit {
                    count ++
                }
            }
        }.joinAll()
        println("result $count")
    }

    /**
     * 避免访问外部可变状态
     * 说明：编写函数时要求避免访问外部可变状态，只能基于参数做运算，
     * 通过返回值提供运算结果
     *
     * @author zhouronghua
     * @time 2022/1/4 8:22 下午
     */
    @Test
    fun test_outer_safe_multi_coroutine() = runBlocking {
        // 并发时一个线程同时运行
        var count = 0
        // 创建10000个并发协程，结果小于预期值
        val result = count + List(10000) {
            GlobalScope.async {
                1
            }
        }.map {
            it.await()
        }.sum()
        println("result $count")
    }
}